<?
/**
 * $Id: sampleTest.php,v 1.11 2005/06/16 16:06:48 japha Exp $
 *
 * This is the main source of documentation for Japha::JpUnit. If you need more, I'd suggest checking out
 * http://www.junit.org, or requesting that I write more comprehensize documentation and add it to the site.
 *
 * Read through this file before you start using JpUnit to unit test your own classes.
 *
 * @author <a href="mailto:gantt@cs.montana.edu">Ryan Gantt</a>
 * @version $Revision: $
 */
 
/**
 * You must include the Japha "VM" in order to use some of these features.. Most importantly, the classes
 * that are utilized in TestCase, TestRunner, Assert, et cetera require Japha classes.
 *
 * The current path may not necessarily be correct, you'll have to figure out where the japha directory
 * is relative to this file.
 */
include '../japha/japha.php';

/**
 * You must include these three files in order to create and run unit tests.
 *
 * While jpunit.framework.Assert is not necessary to include here since it is included in jpunit.framework.TestCase,
 * it is still a good idea to include it since that may not always be the case
 *
 * Which TestRunner you import is dependent on the manner in which you wish to display the results of the tests. By
 * default, JpUnit is programmed to display the results to a browser, but this can be changed by simply writing a 
 * new *ui extension. We are currently working on a 'cliui' extension for printing the results to the command line.
 */
import('jpunit.framework.TestCase');
import('jpunit.framework.Assert');
import('jpunit.ui.textui.TestRunner');

/**
 * In order to begin defining a set of Unit Tests, you need to create a specialized class to do the job. This class
 * must inherit from TestCase in order to use all of the functionality provided by it.
 *
 * You needn't (and shouldn't) define a constructor for this class -- this functionality should be implemented in the
 * <code>setUp</code> method. Think of <code>setUp</code> as your constructor, and <code>tearDown</code> as your 
 * destructor.
 */
class MoneyTest extends TestCase
{
    private $f12CHF;
    private $f14CHF;   

    /**
     * In <code>setUp</code>, I create new Instances of the class that I want to run the unit tests on (namely, "Money", which I 
     * have defined below). This does several things. First, it gets some motion going through the constructor of the Money
     * class, which will provide an implementation specific (although not too reliable) test of the class, and will weed
     * out errors in the constructors. It also sets up some instance objects that I can reference in my other tests.
     */
    protected function setUp() 
    {
        $this->f12CHF = new Money(12, 'CHF');
        $this->f14CHF = new Money(14, 'CHF');
    }

    /**
     * Now, we need to define <code>tearDown</code>. It is generally a good idea (although by no means required) to destroy
     * your instance variables here. The main reason for this is good programming practice and readability. However, I suppose
     * that if you are going to be the only person to ever see your code, it doesn't particularly matter.
     */
    protected function tearDown()
    {
        unset( $this->f12CHF );
        unset( $this->f14CHF );
    }

    /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
    /* Next, we need to define our TestCases. */
    /* In MoneyTest, I have three. Generally  */
    /* the main feature of a test case method */
    /* is the existance of one or more calls  */
    /* to an Assert:: static method.          */
    /* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
    
    /**
     * In my first test case, <code>mustFail</code>, I create a new instance of my test class (<code>Money</code>) manually
     * which I will use later in the method to test against other instances (this is the test of the "equals" method). I then
     * do a check of this instance against a new instance of <code>Money</code> that I know cannot be the same, and Assert
     * that the return value of the <code>$new->equals()</code> method must be true. This will cause an error. If it does not
     * cause an error, then we know that something is wrong with the code defined either in our <code>MoneyTest</code> or
     * <code>Money</code> class. Once you have defined some unit tests that have worked reliably with tested code, you will
     * be able to easy figure out that this error is obviously something wrong with your test class (<code>Money</code).
     * Next, I run the same check again, except this time with a new object that we believe <b>should</b> be the same as $new.
     * We then proceed to Assert that the return value of <code>equals()</code> should be true. This has the same effect
     * as the previous test.
     */
    public function mustFail()
    {
    	$new = new Money(29, "USD");
    	Assert::assertTrue( $new->equals( new Money( 18, "USD" ) ) );	
    	Assert::assertTrue( $new->equals( new Money( 29, "USD" ) ) );
    }
    
    /**
     * In this method, we'll create a new instance of the <code>Money</code> object that we believe should be equivalent
     * to the sum of the two instance <code>Money</code>s that we have defined as private vars. This is a good test of
     * the <code>add()</code> method because it lets us logically anticipate what we think the value is going to be, 
     * and if it results in a different value, then we can throw an exception and know exactly where to look (the
     * <code>add()</code> method).
     */
    public function testSimpleAdd() 
    {
        $expected = new Money(26, "CHF");
        $result = $this->f12CHF->add( $this->f14CHF );
        Assert::assertTrue( $expected->equals( $result ) );
    }
    
    public function testShouldFail()
    {
	    Assert::assertTrue( false );
    }
    
    /**
     * The third and final sample test case simply shows many variations on the theme of testing. In the first assertion,
     * we require the private variable <code>f12CHF</code> to be null (a non instantiated value), which is obviously
     * false. We when try to assert that a false value is true (0 always evaluates to false). Then, we assert that one
     * of our private variable is equal to a value that doesn't even exist, followed by asserting that the same privte
     * var is equal to a new instance of <code>Money</code> with the same characteristics as it. Finally, we assert that
     * the two private variables we've been using the whole time are <b>not</b> equal to each other.
     *
     * Overall, the unit test should come out as follows: The first three assertions should throw errors, and the
     * final two should run perfectly fine
     *
     * Note that this is just an example, and you should never really have more than one assertion per test, because
     * JpUnit will only report one failure per test. If the first assertion fails (which it does), it will not report
     * the other failures caused by invalid assertions. Theoretically and aesthetically, this method should be split up
     * into 5 seperate ones, one for each assertion. This, however, would also cause JpUnit to report 4 failures instead
     * of two. (Note: as soon as you fixed the first failure in this implementation, it will show another failure, instead
     * of showing them all at once).
     */
	public function testEquals()
	{
	    Assert::assertTrue( 1 );
	    Assert::assertEquals( $this->f12CHF, $this->f12CHF );
	    Assert::assertEquals( $this->f12CHF, new Money( 12, "CHF" ) );
	    Assert::assertTrue( !$this->f12CHF->equals( $this->f14CHF ) );
	}
	
	/**
	 * Anytime you subclass TestCase and are planning on defining your own custom test cases, you should overwrite
	 * the suite() method in order to hint the framework about what your methods are called. This example method
	 * creates a new TestSuite (a TestSuite isntance is essentially a collection of objects of type Test), and then
	 * adds our three tests to it. We must pass the name of our custom test method as the parameter to the
	 * <code>MoneyTest</code> constructor, in order for the framework to be able to find our custom tests. Hopefully
	 * you'll notice that the three names being passed to <code>MoneyTest</code> are the names of <b>our</b> three
	 * sample tests
	 *
	 * Once we're done defining our TestSuite, we need to return it so that the method which calls this one will get
	 * something useful out of it and be able to call our custom tests.
	 */
	public static function suite() 
	{
	    $suite = new TestSuite();
	    $suite->addTest( new MoneyTest('mustFail') );
	    $suite->addTest( new MoneyTest('testEquals') );
	    $suite->addTest( new MoneyTest('testShouldFail') );
	    $suite->addTest( new MoneyTest('testSimpleAdd') );
	    $suite->addTestSuite( _Class::forName('MoneyTest') );
	    return $suite;
	}
	
	/**
	 * This is the method that one calls to start the unit testing. Since it is static (we're trying to be as much
	 * like Java as possible here, if you haven't already noticed), we can make a call to it as follows:
	 *
	 * <pre>
	 * MoneyTest::main();
	 * </pre>
	 *
	 * This will run all of the unit tests we have defined in this class.
	 */
	public static function main( $args = array() )
	{
    	    TestRunner::run( MoneyTest::suite() );
	}
}

/**
 * This is a very very simplistic class that we are using as an example to unit test. If you really need documentation
 * in order to understand this class, you may want to wait a while before you start using a unit testing framework.
 *
 * @author <a href="mailto:gantt@cs.montana.edu">Ryan Gantt</a>
 */
class Money extends Object
{
    private $fAmount;
    private $fCurrency;

    public function __construct( $amount, $currency ) 
    {
        $this->fAmount = $amount;
        $this->fCurrency = $currency;
    }

	public function add( Money $m ) 
	{
	    return new Money( $this->amount() + $m->amount(), $this->currency() );
	}
    
    public function amount() 
    {
        return $this->fAmount;
    }

    public function currency() 
    {
        return $this->fCurrency;
    }
    
	public function equals( $anObject ) 
	{
	    if ($anObject instanceof Money) 
	    {
        	$aMoney = $anObject;
        	return ( $aMoney->currency() == $this->currency() ) && $this->amount() == $aMoney->amount();
	    }
	    return false;
	}
}

/**
 * This is where we start and run the unit tests we have defined in <code>MoneyTest</code>
 *
 * If there are any errors, there will be custom stacktraces printed out for them. We are using the default printing
 * mechanism, which is the textui.TestRunner/ResultPrinter, which will simply output all of the data to the browser.
 *
 * One could implement a new way to output the data, via PHP-GTK or XML-RSS or something.
 */
MoneyTest::main();
?>
